package org.lc.cmd.plugin.scan;

import org.jline.reader.Candidate;
import org.jline.reader.ParsedLine;
import org.lc.cmd.CmdParam;
import org.lc.cmd.Command;
import org.lc.cmd.CommandRegistry;
import org.lc.cmd.DataCompleter;
import org.lc.cmd.IndexParam;
import org.lc.cmd.OptParam;
import org.lc.cmd.impl.SolonCommand;
import org.lc.cmd.plugin.anno.Cmd;
import org.lc.cmd.plugin.anno.CmdField;
import org.lc.cmd.util.CmdOutUtil;
import org.lc.cmd.util.CollectionUtil;
import org.lc.cmd.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Cmd(value = "help", description = "帮助")
@Order(100)
public class HelpController {
    @Autowired
    private CommandRegistry commandRegistry;

    public static String formatCmdParam(CmdParam param, String prefix) {
        StringBuilder sb = new StringBuilder(prefix);
        if (param instanceof OptParam) {
            OptParam optParam = (OptParam) param;
            if (CollectionUtil.isNotEmpty(optParam.getShortOpts())) {
                sb.append(optParam.getShortOpts().stream().map(opt -> "-" + opt).collect(Collectors.joining(",")));
                if (optParam.isWithParamData()) {
                    sb.append("=<data>");
                }
            }
            if (CollectionUtil.isNotEmpty(optParam.getLongOpts())) {
                if (CollectionUtil.isNotEmpty(optParam.getShortOpts())) {
                    sb.append("\t");
                }
                sb.append(optParam.getLongOpts().stream().map(opt -> "--" + opt).collect(Collectors.joining(",")));
                if (optParam.isWithParamData()) {
                    sb.append("=<数据>");
                }
                sb.append(' ');
            }
            sb.append("\t").append(param.getName());
        } else if (param instanceof IndexParam) {
            sb.append("<").append(param.getName()).append(">");
        }
        if (StringUtil.isNotEmpty(param.getDescription())) {
            sb.append("\t").append(param.getDescription());
        }
        if (param.isRequired()) {
            sb.append("\t必填");
        }
        if (param.isMultiple()) {
            sb.append("\t可多次传参");
        }
        return sb.toString();
    }

    public static String formatCmdParam(CmdParam param) {
        return formatCmdParam(param, "");
    }

    @Cmd(description = "帮助的实现") // todo 输出彩色help命令
    public String help(
            @CmdField(paramType = CmdField.Type.INDEX, description = "命令", completer = CommandCompleter.class) String command,
            @CmdField(paramType = CmdField.Type.INDEX, description = "子命令", completer = SubCmdCompleter.class) String subCommand,
            @CmdField(description = "查看详细信息") boolean info) {
        Map<String, Command> commands = commandRegistry.getCommands();
        if (StringUtil.isEmpty(command)) {
            return cmdOverview(commands, info);
        }
        Command classCmd = commands.get(command);
        if (classCmd == null) {
            return "没有找到命令信息";
        }
        if (StringUtil.isEmpty(subCommand)) {
            return cmdOverview(Collections.singletonMap(command, classCmd), info);
        }
        if (classCmd instanceof SolonCommand) {
            SolonCommand solonCmd = (SolonCommand) classCmd;
            return methodCmdDataInfo(solonCmd, solonCmd.getSubCmdMap().get(subCommand), "");
        }
        return "暂不支持命令[" + command + "]的帮助信息";
    }

    public String cmdOverview(Map<String, Command> commands, boolean info) {
        if (CollectionUtil.isEmpty(commands)) {
            return "没有找到命令信息\n";
        }
        StringBuilder sb = new StringBuilder();
        commands.forEach((name, command) -> {
            sb.append(name).append(" ").append(command.getDescription()).append("\n");
            if (!(command instanceof SolonCommand)) {
                sb.append("暂不支持获取此命令的帮助信息\n");
                return;
            }
            SolonCommand soloCmd = (SolonCommand) command;
            if (soloCmd.getSubCmdMap() != null) {
                soloCmd.getSubCmdMap().forEach((subName, subCmd) -> {
                    sb.append("\t").append(subName).append(" ").append(subCmd.getDescription()).append("\n");
                    if (info) {
                        sb.append(methodCmdDataInfo(soloCmd, subCmd, "\t"));
                    }
                });
            }
        });
        return sb.toString();
    }

    public String methodCmdDataInfo(SolonCommand classCmd, SolonCommand.SolonMethodCommand methodCmd, String prefix) {
        StringBuilder sb = new StringBuilder();
        // line 1
        sb.append(prefix).append("用法: ").append(classCmd.getName());
        if (StringUtil.isNotEmpty(methodCmd.getName())) {
            sb.append(" ").append(methodCmd.getName());
        }
        List<CmdParam> params = methodCmd.getParams();
        if (params.stream().anyMatch(p -> p instanceof OptParam)) {
            sb.append(" ").append("[选项]");
        }
        List<IndexParam> indexParams =
                params.stream().filter(p -> p instanceof IndexParam).map(p -> ((IndexParam) p)).sorted(Comparator.comparing(IndexParam::getIndex)).collect(Collectors.toList());
        for (IndexParam indexParam : indexParams) {
            sb.append(" ");
            if (!indexParam.isRequired()) {
                sb.append("[");
            }
            sb.append("<").append(indexParam.getName()).append(">");
            if (!indexParam.isRequired()) {
                sb.append("]");
            }
        }
        // 循环参数
        List<IndexParam> loopIndexParams =
                indexParams.stream().filter(CmdParam::isMultiple).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(loopIndexParams)) {
            sb.append(" [");
            boolean first = true;
            for (IndexParam indexParam : loopIndexParams) {
                if (!first) {
                    sb.append(" ");
                }
                sb.append("<").append(indexParam.getName()).append(">");
                first = false;
            }
            sb.append("]");
        }
        sb.append("\n");

        // 选项列表
        for (CmdParam param : params) {
            if (param instanceof OptParam) {
                sb.append(formatCmdParam(param, prefix + "\t")).append("\n");
            }
        }
        return sb.toString();
    }

    @Component
    public static class CommandCompleter implements DataCompleter {
        @Autowired
        private CommandRegistry commandRegistry;

        @Override
        public void complete(SolonCommand cmd, SolonCommand.SolonMethodCommand subCmd, CmdParam param,
                String currentData,
                List<Candidate> candidates, String prefix, ParsedLine line,
                Supplier<Map<String, Object>> parseFunc) {
            Map<String, Command> commands = commandRegistry.getCommands();
            commands.forEach((k, v) -> {
                if (k.startsWith(currentData)) {
                    candidates.add(new Candidate(prefix + k, k, null, v.getDescription(), null, null, true));
                }
            });
        }
    }

    @Component
    public static class SubCmdCompleter implements DataCompleter {
        @Autowired
        private CommandRegistry commandRegistry;

        @Override
        public void complete(SolonCommand cmd, SolonCommand.SolonMethodCommand subCmd, CmdParam param,
                String currentData,
                List<Candidate> candidates, String prefix, ParsedLine line,
                Supplier<Map<String, Object>> parseFunc) {
            Map<String, Object> params = parseFunc.get();
            String command = (String) params.get("command");
            if (StringUtil.isEmpty(command)) {
                CmdOutUtil.writeError("无法获取命令参数", true);
                return;
            }
            Map<String, Command> commands = commandRegistry.getCommands();
            Command queryCmd = commands.get(command);
            if (queryCmd == null) {
                CmdOutUtil.writeError("找不到命令：" + command, true);
                return;
            }
            SolonCommand solonCommand = queryCmd instanceof SolonCommand ? ((SolonCommand) queryCmd) : null;
            if (solonCommand == null) {
                CmdOutUtil.writeError("不支持的命令：" + command, true);
                return;
            }
            solonCommand.getSubCmdMap().forEach((k, v) -> {
                if (k.startsWith(currentData)) {
                    candidates.add(new Candidate(k, k, null, v.getDescription(), null, null, true));
                }
            });
        }
    }
}
